//============================================================================================
/**
 * @file	dungeon_cutin.c
 * @brief	ダンジョンカットイン
 * @date	2007.11.02
 * @author	Nozomu Saito
 */
//============================================================================================
#include "common.h"
#include "system/arc_util.h"
#include "system/wipe.h"
#include "system/fontproc.h"
#include "system/timezone.h"

//#include "system/msgdata.h"

#include "dungeon_cutin.h"
#include "dungeon_cutin_def.h"
#include "msgdata/msg_dungeon_cutin.h"
#include "mapdefine.h"

#include "dungeoncut.naix"
#include "dungeon_cutin.dat"

#include "fieldsys.h"
#include "field_event.h"
#include "fieldmap.h"

#include "msgdata/msg.naix"						//NARC_msg_??_dat
#include "msgdata/msg_dungeon_cutin.h"


//----------------------------------------------------------
//バグフィックス
//----------------------------------------------------------
#if	GS_BTS5520_20090708_FIX
#include "pair_poke.h"
#endif

#define DCI_DISP_TIME	(60)
#define DCI_ALPHA_COUNT_WAIT	(2)
#define ALPHA_MAX		(16)

#define PALLETE_MAX		(11)			//パレット１１本
#define CUTIN_FRAME		FLD_MBGFRM_EFFECT2

#define DUNGEONCUT_TEXT_X			( 0  )
#define DUNGEONCUT_TEXT_Y			( 0  )
#define DUNGEONCUT_TEXT_W			( 28 )
#define DUNGEONCUT_TEXT_H			( 2  )
#define DUNGEONCUT_TEXT_PAL			( 13 )
#define DUNGEONCUT_TEXT_CHAR_OFFSET	( 32*22 )

#define	DUN_NAME_X	(8)	//ダンジョン名表示X位置
#define	DUN_NAME_Y	(0)		//ダンジョン名表示Y位置

#define LADDER_MOVE_SPEED	(FX32_ONE*2)
#define LADDER_MOVE_COUNT	(16)

typedef struct LADDER_ANM_WORK_tag
{
	u16 Seq;
	u16 YAddCount;
}LADDER_ANM_WORK;

typedef struct  EVENT_DCI_WORK_tag
{
	int Seq;
	int DispTimer;
	int HeapID;
	GF_BGL_INI *bgl;
	GF_BGL_BMPWIN *Win;
	u16 ColorMode;
	u16 CutinNo;
	u16 Alpha;
	u16 AlphaCount;

	int BGPriority[4];

	int TimeZone;
	BOOL LadderDownAnm;		//ダンジョンカットインの中には、階段アニメが入るものがあるらしい
	LADDER_ANM_WORK LadderAnmWork;
}EVENT_DCI_WORK;

static BOOL CutInEvent(GMEVENT_CONTROL * event);
static void SetDungeonGraphic( EVENT_DCI_WORK *wk );
static void SetDungeonName( EVENT_DCI_WORK *wk );
static void PrintDungeonName(EVENT_DCI_WORK *wk);
static BOOL PlayerMoveMain(EVENT_DCI_WORK * dciw, FIELDSYS_WORK * fsys);

//------------------------------------------------------------------
/**
 * @brief   ダンジョンカットインチェック
 *
 * @param   inZoneID		ゾーンID
 *
 * @retval  u8 ダンジョンカットインナンバー
 */
//------------------------------------------------------------------
const u8 DCI_CheckZone(const int inZoneID)
{
	u8 cutin_no;
	int i;

	cutin_no = DUNGEON_CUTIN_NONE;
	for(i=0;i<DUNGEON_CUTIN_NUM;i++){
		if (DungeonCutinData[i].ZoneID == inZoneID){
			cutin_no = i;
			break;
		}
	}
	return cutin_no;
}

//------------------------------------------------------------------
/**
 * @brief   ダンジョンカットインイベントコール
 *
 * @param   event			イベントポインタ
 * @param	inCutinNo		カットインナンバー
 * @param	inTimeZone		時間帯
 * @param	inAnm			自機がアニメする？
 *
 * @retval  none
 */
//------------------------------------------------------------------
void DCI_EventCall(GMEVENT_CONTROL * event, const u8 inCutinNo, const u8 inTimeZone, const BOOL inAnm)
{
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	//メモリ確保
	EVENT_DCI_WORK *wk = sys_AllocMemoryLo(HEAPID_FIELD, sizeof(EVENT_DCI_WORK));
	//メンバのセット
	wk->Seq = 0;
	wk->DispTimer = 0;
	wk->bgl = FieldBglIniGet( fsys );
	wk->Alpha = 0;
	wk->AlphaCount = 0;

	wk->CutinNo = inCutinNo;

	switch(inTimeZone){
	case TIMEZONE_MORNING:
		wk->TimeZone = 0;
		break;
	case TIMEZONE_NOON:
		wk->TimeZone = 1;
		break;
	case TIMEZONE_EVENING:
		wk->TimeZone = 2;
		break;
	case TIMEZONE_NIGHT:
	case TIMEZONE_MIDNIGHT:
		wk->TimeZone = 3;
		break;
	default:
		GF_ASSERT(0);
		wk->TimeZone = 0;
	}
	wk->HeapID = HEAPID_FIELD;

	wk->LadderDownAnm = inAnm;
	wk->LadderAnmWork.Seq = 0;
	wk->LadderAnmWork.YAddCount = 0;

	//イベントコール
	FieldEvent_Call(event, CutInEvent, wk);
}

//------------------------------------------------------------------
/**
 * @brief   イベント
 *
 * @param   event		イベントポインタ
 *
 * @retval  BOOL		TRUE:イベント終了　 FALSE;イベント継続
 */
//------------------------------------------------------------------
static BOOL CutInEvent(GMEVENT_CONTROL * event)
{
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	EVENT_DCI_WORK * dciw = FieldEvent_GetSpecialWork(event);
	switch (dciw->Seq) {
	case 0:		//初期化
		//カラーモード保存
		dciw->ColorMode = GF_BGL_ScreenColorModeGet( dciw->bgl, CUTIN_FRAME );
		//プライオリティ保存
		dciw->BGPriority[0] = GF_BGL_PriorityGet( dciw->bgl, CUTIN_FRAME );
		dciw->BGPriority[1] = GF_BGL_PriorityGet( dciw->bgl, FLD_MBGFRM_MAP );
		dciw->BGPriority[2] = GF_BGL_PriorityGet( dciw->bgl, FLD_MBGFRM_EFFECT1 );
		dciw->BGPriority[3] = GF_BGL_PriorityGet( dciw->bgl, FLD_MBGFRM_FONT );
		//BGL再設定
		GF_BGL_BGControlReset( dciw->bgl, CUTIN_FRAME, BGL_RESET_COLOR, GX_BG_COLORMODE_256 );
		//プライオリティセット
		GF_BGL_PrioritySet( FLD_MBGFRM_FONT, 0 );
		GF_BGL_PrioritySet( CUTIN_FRAME, 1 );
		GF_BGL_PrioritySet( FLD_MBGFRM_MAP, 2 );

		// ダンジョンカットイングラフィック転送
		SetDungeonGraphic( dciw );
		//ダンジョン名プリント
		SetDungeonName(dciw);
		//アルファセット
		G2_SetBlendAlpha( GX_BLEND_PLANEMASK_BG2,
			GX_BLEND_PLANEMASK_BG0|GX_BLEND_PLANEMASK_BD, ALPHA_MAX, 0 );

		//ワイプスタート
		WIPE_SYS_Start( WIPE_PATTERN_WMS, WIPE_TYPE_FADEIN, WIPE_TYPE_FADEIN, WIPE_FADE_BLACK, 16, 1, dciw->HeapID );

		//この時点でのヒープの残りを確認
		dciw->Seq++;
		break;
	case 1:		//ワイプ待ち
		if(WIPE_SYS_EndCheck( )){
			dciw->Seq++;
		}
		break;
	case 2:		//メイン
		if (sys.trg & PAD_BUTTON_A){	//カットインスキップ
			//クロスフェード開始
			dciw->Alpha = 0;
			dciw->Seq++;
		}else{
			//タイマー
			if (++dciw->DispTimer > DCI_DISP_TIME){
				//クロスフェード開始
				dciw->Alpha = 0;
				dciw->Seq++;
			}
		}
		break;
	case 3:		//クロスフェード待ち
		if ( dciw->Alpha < ALPHA_MAX) {
			if ( ++dciw->AlphaCount >= DCI_ALPHA_COUNT_WAIT ){
				dciw->AlphaCount = 0;
				dciw->Alpha++;
			}
			G2_ChangeBlendAlpha(ALPHA_MAX - dciw->Alpha, dciw->Alpha);
		}


		if ( PlayerMoveMain(dciw,fsys)&&(dciw->Alpha >= ALPHA_MAX) ){
			//クロスフェード終了
			GF_BGL_VisibleSet(CUTIN_FRAME, VISIBLE_OFF);		//カットイン面非表示
			//カラーモード復帰
			GF_BGL_BGControlReset( dciw->bgl, CUTIN_FRAME, BGL_RESET_COLOR, dciw->ColorMode );
			//プライオリティ復帰
			GF_BGL_PrioritySet( CUTIN_FRAME, dciw->BGPriority[0] );
			GF_BGL_PrioritySet( FLD_MBGFRM_MAP, dciw->BGPriority[1] );
			GF_BGL_PrioritySet( FLD_MBGFRM_EFFECT1, dciw->BGPriority[2] );
			GF_BGL_PrioritySet( FLD_MBGFRM_FONT, dciw->BGPriority[3] );
			//ブレンド効果クリア
			G2_BlendNone();
			GF_BGL_ClearCharSet( CUTIN_FRAME, 32, 0, dciw->HeapID );
			GF_BGL_ScrClear( dciw->bgl, CUTIN_FRAME );
			//BMP解放
			GF_BGL_BmpWinFree(dciw->Win,1);
			//メモリ解放
			sys_FreeMemoryEz(dciw);
			return TRUE;
		}
		break;
	}

	return FALSE;
}

//------------------------------------------------------------------
/**
 * @brief   ダンジョンカットイングラフィック転送
 *
 * @param	wk	ワーク
 *
 * @retval  none
 */
//------------------------------------------------------------------
static void SetDungeonGraphic( EVENT_DCI_WORK *wk )
{
	ArcUtil_PalSet( ARC_DUNGEONCUT_GRA,
					DungeonCutinData[wk->CutinNo].Graphic[wk->TimeZone][0],
					PALTYPE_MAIN_BG,0,PALLETE_MAX*0x20, wk->HeapID);
	ArcUtil_BgCharSet( ARC_DUNGEONCUT_GRA,
					   DungeonCutinData[wk->CutinNo].Graphic[wk->TimeZone][1],
					   wk->bgl,CUTIN_FRAME,0,0,1, wk->HeapID);
	ArcUtil_ScrnSet( ARC_DUNGEONCUT_GRA,
					 DungeonCutinData[wk->CutinNo].Graphic[wk->TimeZone][2],
					 wk->bgl,CUTIN_FRAME,0,0,1, wk->HeapID);
	{
/**		NNSG2dPaletteData * pal_dat;
		void * buf;
		buf = ArcUtil_PalDataGet( ARC_AREA_WIN_GRA, 0+1, &pal_dat, HEAPID_FIELD );
		DC_FlushRange( pal_dat->pRawData, 32 );
		GX_LoadBGPltt( pal_dat->pRawData, 7 * 32, 32 );
		sys_FreeMemoryEz( buf );
		G2_SetBG3Priority(0);
		G2_SetBG2Priority(1);
		G2_SetBG0Priority(2);*/
	}
}

//------------------------------------------------------------------
/**
 * @brief   BMPセット
 *
 * @param	wk	ワーク
 *
 * @retval  none
 */
//------------------------------------------------------------------
static void SetDungeonName( EVENT_DCI_WORK *wk )
{
	wk->Win=GF_BGL_BmpWinAllocGet(wk->HeapID,1);
	GF_BGL_BmpWinAdd( wk->bgl, wk->Win, CUTIN_FRAME,
		DUNGEONCUT_TEXT_X, DUNGEONCUT_TEXT_X, DUNGEONCUT_TEXT_W, DUNGEONCUT_TEXT_H,
		DUNGEONCUT_TEXT_PAL, DUNGEONCUT_TEXT_CHAR_OFFSET);
///	PrintDungeonName(wk);
}

//--------------------------------------------------------------
/**
 * @brief	メッセージ表示
 *
 * @param	wk	ワーク
 *
 * @retval	none
 */
//--------------------------------------------------------------
static void PrintDungeonName(EVENT_DCI_WORK *wk)
{
	MSGDATA_MANAGER		*msg_m;
	STRBUF				*msg_buf;

	GF_BGL_BmpWinDataFill(wk->Win,13*16+14);	//パレット13番14色目

	msg_buf = STRBUF_Create(0x100, wk->HeapID);

	//ダンジョン名
	msg_m = MSGMAN_Create(MSGMAN_TYPE_DIRECT,ARC_MSG,NARC_msg_dungeon_cutin_dat, wk->HeapID);
	MSGMAN_GetString( msg_m, DungeonCutinData[wk->CutinNo].Name, msg_buf);
	MSGMAN_Delete(msg_m);
	GF_STR_PrintColor(wk->Win,FONT_SYSTEM,msg_buf,DUN_NAME_X,DUN_NAME_Y,0,GF_PRINTCOLOR_MAKE(15,2,14),NULL);

	sys_FreeMemoryEz(msg_buf);
}

//--------------------------------------------------------------
/**
 * @brief	梯子アニメ
 *
 * @param	dciw	ワーク
 * @param	fsys	フィールドシステムポインタ
 *
 * @retval	none
 */
//--------------------------------------------------------------
static BOOL PlayerMoveMain(EVENT_DCI_WORK * dciw, FIELDSYS_WORK * fsys)
{
	FIELD_OBJ_PTR fop;
	LADDER_ANM_WORK *pWork;

	if (!dciw->LadderDownAnm){
		return TRUE;
	}

	pWork = &dciw->LadderAnmWork;

	switch(pWork->Seq){
	case 0:
		//自機の高さ自動取得をオン
		Player_HeightGetSet_ON_OFF( fsys->player, FALSE );
		(pWork->Seq) ++;
		break;
	case 1:	//自機移動
		{
			VecFx32 vec;
			fop = Player_FieldOBJGet( fsys->player );
			pWork->YAddCount++;
			//自機高さ変更
			FieldOBJ_VecPosGet( fop, &vec );
			vec.y -= LADDER_MOVE_SPEED;
			FieldOBJ_VecPosSet( fop, &vec );
			if (pWork->YAddCount >= LADDER_MOVE_COUNT){
				//自機の高さ自動取得をオン
				Player_HeightGetSet_ON_OFF( fsys->player, TRUE );
				(pWork->Seq) ++;
			}
		}
		break;
	case 2:		//自機を元に戻す
		{
			Player_RequestSet( fsys->player, HERO_REQBIT_NORMAL );
			Player_Request( fsys->player );
		}
		(pWork->Seq) ++;
		break;
	case 3:
		fop = Player_FieldOBJGet( fsys->player );
		//自機アニメできるなら、下向きにする
		if( FieldOBJ_AcmdSetCheck(fop)){
			FieldOBJ_AcmdSet(fop,AC_DIR_D);
			(pWork->Seq) ++;
		}
		break;
	case 4:	//アニメ待ち
		fop = Player_FieldOBJGet( fsys->player );
		if ( FieldOBJ_AcmdSetCheck(fop) ) {

#if	GS_BTS5520_20090708_FIX
			if (PairPoke_IsPairPoke(fsys)){
				//連れ歩きポケモンを自機と重ねる
				PairPoke_SetPlayerPos(fsys, DIR_DOWN);
				//1つ前のマップで自転車に乗っていたことを考え連れ歩き動作コードセットしなおす
				FieldOBJ_MoveCodeChange( PairPoke_GetFldObjPtr(fsys), MV_PAIR );
				//1歩移動で連れ歩き表示状態にする
				PairPoke_StartVanish(PairPoke_GetFldObjPtr(fsys), TRUE);
			}
#else
			//自転車の場合は戻す
			int form = Player_FormGet(fsys->player);
			if ( form == HERO_FORM_CYCLE){
				u32 req_bit = Player_FormRequestGet( form );
				Player_RequestSet( fsys->player, req_bit );
				Player_Request( fsys->player );
			}
#endif
			(pWork->Seq) ++;
		}
		break;
	case 5:
		return TRUE;
	}

	return FALSE;
}